
#include "mathlib.h"

#include <vector>
#include <cmath>
#include "stdtypes.h"


namespace Geometry
{
// The value of pi (taking straight from calc.exe.)
const f32_t Pi = 3.1415926535897932384626433832795f;

// John Carmack's fast rsqrt func, finds 1/sqrt(number) -- from Quake III: Q_rsqrt
// To get sqrt: 1.0f / ReciprocalSqrt(val) -- though testing shows that just calling
// std::sqrt is faster.  This function is useful if you want to normalize a vector,
// though, because in reality you need 1 / sqrt(length)
float ReciprocalSqrt(f32_t number)
{
	// *** warning, hack alert *** not from a digipen student, but from id software.
	// In floats from 0.0f - 1000000.0f, the maximum error is 1.7 assuming we use
	// the code to emulate sqrt().  That's a small error, so this code is good for quick
	// but not completely accurate reciprocal squareroots.

	f32_t x2 = number * 0.5f;

	int32_t i  = *reinterpret_cast<int32_t*>(&number);		// evil floating point bit level hacking
	i  = 0x5f3759df - ( i >> 1 );               // what the fuck?

	f32_t y  = *reinterpret_cast<f32_t*>(&i);
	y  = y * ( 1.5f - ( x2 * y * y ) );   // 1st iteration
	//y  = y * ( 1.5f - ( x2 * y * y ) );   // 2nd iteration, can be removed (was removed in Q3 source)

	return y;
}

} // namespace Geometry




///////////////////////////////////////////////////////////////////////////////
// Here, I implemented a robust sine table and then found out through profiling
// that std::sin is actually really, really fast. #define USE_SINE_TABLE_IMPL
// to use compile the sine table code.  --jjensen 8/25/05
///////////////////////////////////////////////////////////////////////////////

#ifdef USE_SINE_TABLE_IMPL

namespace
{ // unnamed namespace for implementation details

const uint32_t TABLE_SIZE = 256; // must be a power of two

// Class that creates a sine table. The size of the table is specified by a
// template parameter.
template<uint32_t _TableSize>
class SineTable
{
public:
	static SineTable* Instance() // singleton
	{
		static SineTable table(_TableSize);
		return &table;
	}

	f32_t GetSine(f32_t rad) const
	{
#if 1
		// Game Programming Gems 2 : Use biasing trick for fast float to int conversion.
		// Portions Copyright (C) Yossarian King, 2001
		INTORFLOAT  fi;
		fi.f = rad * static_cast<f32_t>(_TableSize) / (2.0f * Math::Pi) + bias.f;
		// Scale to table index range and add conversion bias.

		return table_[fi.i & (_TableSize - 1u)];
		// Mask off lower bits, assuming _TableSize is power of 2.

#else
		uint32_t index = static_cast<uint32_t>(rad * static_cast<f32_t>(_TableSize)
			/ (2.0f * Geometry::Pi)) & (_TableSize - 1u);
		return table_[index];
#endif
	}

private:
	SineTable(uint32_t size)
	{
		const f32_t scale = static_cast<f32_t>(size) / (2.0f * Geometry::Pi);

		for (uint32_t i = 0u; i < size; ++i)
		{
			f32_t theta = static_cast<f32_t>(i) / scale;
			table_[i] = std::sin(theta);
		}
	}

	f32_t table_[_TableSize];

	typedef union
	{
		uint32_t i;          // as integer
		f32_t    f;          // as float
	}
	INTORFLOAT;

	static const INTORFLOAT bias;
};

typedef SineTable<TABLE_SIZE> sintable_t;
const sintable_t::INTORFLOAT sintable_t::bias = {((23u + 127u) << 23u) + (1u << 22u)};

} // unnamed namespace

namespace Math
{
f32_t cos(f32_t rad)
{
	const sintable_t* st = sintable_t::Instance();
	return st->GetSine(rad + Pi / 2.0f);
}

f32_t sin(f32_t rad)
{
	const sintable_t* st = sintable_t::Instance();
	return st->GetSine(rad);
}

f32_t tan(f32_t rad)
{
	return std::tan(rad);
}

}

#endif // USE_SINE_TABLE_IMPL
